package com.drawing.common.util;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;

/**
 * @author zhaozhenhang <zhaozhenhang@kuaishou.com>
 * Created on 2023-10-10
 */
public class CustomizedTypeAdapter extends TypeAdapter<Object> {

    private static final class LazyHolder {

        static final TypeAdapter<Object> LAZY = new Gson().getAdapter(Object.class);
    }

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        LazyHolder.LAZY.write(out, value);
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        switch (token) {
            case BEGIN_ARRAY:
                List<Object> list = new ArrayList<>();
                in.beginArray();
                while (in.hasNext()) {
                    list.add(read(in));
                }
                in.endArray();
                return list;

            case BEGIN_OBJECT:
                Map<String, Object> map = new HashMap<>();
                in.beginObject();
                while (in.hasNext()) {
                    map.put(in.nextName(), read(in));
                }
                in.endObject();
                return map;

            case STRING:
                return in.nextString();

            case NUMBER: // override, 用BigDecimal的exact方法, 当产生精度丢失或溢出时, 会抛出ArithmeticException
                BigDecimal bigDecimal = new BigDecimal(in.nextString());
                try { // 先尝试转为int
                    return bigDecimal.intValueExact();
                } catch (ArithmeticException e) {
                    try { // 转int有异常则尝试转为long
                        return bigDecimal.longValueExact();
                    } catch (ArithmeticException e2) {
                        return bigDecimal.doubleValue();
                    }
                }
            case BOOLEAN:
                return in.nextBoolean();

            case NULL:
                in.nextNull();
                return null;

            default:
                throw new IllegalStateException();
        }
    }
}
